package com.ctshk.rpc.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.GlobalConstants;
import com.ctshk.common.enums.IsDeletedCode;
import com.ctshk.common.enums.PermissionDataType;
import com.ctshk.common.enums.SystemError;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.common.utils.SnowflakeIdWorker;
import com.ctshk.rpc.system.dto.PermissionDataDTO;
import com.ctshk.rpc.system.dto.PermissionMenuDTO;
import com.ctshk.rpc.system.dto.PermissionUserMenuDTO;
import com.ctshk.rpc.system.dto.SysMenuActionButtonDTO;
import com.ctshk.rpc.system.entity.*;
import com.ctshk.rpc.system.enums.MenuType;
import com.ctshk.rpc.system.mapper.*;
import com.ctshk.rpc.system.req.PermissionDataReq;
import com.ctshk.rpc.system.req.PermissionDataScopeReq;
import com.ctshk.rpc.system.service.ISysDepartmentService;
import com.ctshk.rpc.system.service.ISysMenuService;
import com.ctshk.rpc.system.service.ISysPermissionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 权限 服务实现类
 * </p>
 *
 * @author 谢诗宏
 * @since 2020-12-25
 */
@Slf4j
@DubboService
public class SysPermissionServiceImpl extends ServiceImpl<SysPermissionMapper, SysPermission> implements ISysPermissionService {

    @Autowired
    private SysPermissionMapper sysPermissionMapper;

    @Autowired
    private SysMenuMapper sysMenuMapper;

    @Autowired
    private SysPermissionDataMapper sysPermissionDataMapper;

    @Autowired
    private SysDepartmentMapper sysDepartmentMapper;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private ISysDepartmentService sysDepartmentService;

    @Autowired
    private ISysMenuService sysMenuService;

    @Autowired
    private SysPermissionDataServiceImpl sysPermissionDataService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean setMenuPermission(long topId, List<Long> menuIds,
                                     long userId, Integer menuType,
                                     long optUserId,boolean isAdd) {
        /**
         * 设置权限前先去除权限进行重置
         */
        if(isAdd){
            // 获取当前topId的所有子节点
            List<SysMenu> sysMenus = sysMenuMapper.selectChildrenALLStatus(topId);
            // 第一步:去除一级菜单权限
            sysPermissionMapper.delete(Wrappers.<SysPermission>lambdaQuery()
                    .eq(SysPermission::getMenuId, topId)
                    .eq(SysPermission::getUserId, userId));
            // 第二步:去除所有子级菜单权限
            sysMenus.forEach(sysMenu -> {
                sysPermissionMapper.delete(Wrappers.<SysPermission>lambdaQuery()
                        .eq(SysPermission::getMenuId, sysMenu.getId())
                        .eq(SysPermission::getUserId, userId));
            });
        }
        // 添加权限
        menuIds.forEach(menuId -> {
            try {
                SysMenu sysMenu = sysMenuMapper.selectById(menuId);
                SysPermission sysPermission = new SysPermission();
                sysPermission.setMenuId(menuId);
                sysPermission.setUserId(userId);
                if (sysMenu != null) {
                    sysPermission.setMenuType(sysMenu.getMenuType() == null ? 1 : sysMenu.getMenuType());
                } else {
                    sysPermission.setMenuType(1);
                }
                sysPermission.setCreateId(optUserId);
                int insert = sysPermissionMapper.insert(sysPermission);
                if (insert > 0) {
                    newThreadStart(menuId, userId, PermissionDataType.TYPE_3.getCode(), optUserId);
                }
//                log.error("添加重复权限成功！menuId[{}], userId[{}]", menuId, userId);
            } catch (Exception e) {
                if (e.getCause() instanceof java.sql.SQLIntegrityConstraintViolationException) {
                    log.error("添加重复权限失败！重复菜单id和用户id,将取消当前赋予权限操作,menuId[{}], userId[{}]", menuId, userId);
                }
            }
        });

        return true;
    }

    @Override
    public boolean setMenuPermissionData(PermissionDataReq permissionDataReq, long optUserId) {
        //设置权限的用户必须有这个菜单的权限，没有这个菜单的权限就不能设置其下面的子权限
        SysPermission sysPermission = sysPermissionMapper.selectOne(Wrappers.<SysPermission>lambdaQuery()
                .eq(SysPermission::getMenuId, permissionDataReq.getMenuId())
                .eq(SysPermission::getUserId, permissionDataReq.getUserId()));
        //不是功能页的菜单ID不予理会
        if (sysPermission == null || !MenuType.PAGE.getCode().equals(sysPermission.getMenuType())) {
            throw new BusinessException(SystemError.SYS_441);
        }
        if(permissionDataReq.isAddFlage()){
            //######## 第一步: 先修改sysPermission功能页权限类型
            sysPermission.setDataType(permissionDataReq.getDataType());
            sysPermission.setModifiedId(optUserId);
            int i = sysPermissionMapper.updateById(sysPermission);
            if (i < 1) {
                throw new BusinessException(SystemError.SYS_442);
            }
            //####### 第二步: 先删除再新增功能按钮权限
            // 清除当前菜单下指定用户所有的功能按钮权限
            // 先查询出当前菜单下所有的按钮id
            QueryWrapper<SysMenu> qwsm = new QueryWrapper<>();
            qwsm.lambda().eq(SysMenu::getParentId, permissionDataReq.getMenuId())
                    .eq(SysMenu::getIsDeleted, IsDeletedCode.NO.getCode());
            List<SysMenu> sysMenus = sysMenuMapper.selectList(qwsm);
            // 再根据按钮id数组批量删除权限数据
            if (sysMenus != null && sysMenus.size() > 0) {
                List<Long> collecsMenuIds = sysMenus.stream().map(e -> e.getId()).collect(Collectors.toList());
                sysPermissionMapper.delete(Wrappers.<SysPermission>lambdaQuery()
                        .in(CollectionUtils.isNotEmpty(collecsMenuIds), SysPermission::getMenuId, collecsMenuIds)
                        .eq(SysPermission::getUserId, permissionDataReq.getUserId()));
            }
        }

        // 新增当前菜单下指定用户的功能按钮权限
        if (permissionDataReq.getButtonIds() != null && permissionDataReq.getButtonIds().size() > 0) {
            List<SysPermission> listAll = new ArrayList<>();
            permissionDataReq.getButtonIds().forEach(buttonId -> {
                SysPermission permission = new SysPermission();
                permission.setId(SnowflakeIdWorker.nextId());
                permission.setMenuId(buttonId);
                permission.setMenuType(MenuType.BUTTON.getCode());
                permission.setUserId(permissionDataReq.getUserId());
                permission.setDataType(permissionDataReq.isAddFlage()?permissionDataReq.getDataType():sysPermission.getDataType());
                permission.setCreateId(optUserId);
                listAll.add(permission);
            });
            try {
                super.saveBatch(listAll);
            } catch (Exception e) {
                if (e.getCause() instanceof java.sql.SQLIntegrityConstraintViolationException) {
                    log.error("添加重复权限失败！重复菜单id和用户id,将取消当前赋予权限操作,menuId[{}], userId[{}]", permissionDataReq.getMenuId(), permissionDataReq.getUserId());
                }
            }
        }

        // 当数据权限范围为4(自定义)时,重置用户数据权限范围
        if (permissionDataReq.getDataType() == PermissionDataType.TYPE_4.getCode()) {
            if (CollUtil.isEmpty(permissionDataReq.getDepts()) && CollUtil.isEmpty(permissionDataReq.getEmployees())) {
                throw new BusinessException(SystemError.SYSTEM_2000);
            }
            // 第一步: 置空当前菜单下的所有数据权限范围
            sysPermissionDataMapper.delete(Wrappers.<SysPermissionData>lambdaQuery().eq(SysPermissionData::getPermissionId, sysPermission.getId()));
            // 第二步 1): 重新添加当前菜单下的数据部门权限范围
            List<SysPermissionData> listSPD = new ArrayList<>();
            permissionDataReq.getDepts().forEach(permissionDataScopeReq -> {
                SysPermissionData sysPermissionData = new SysPermissionData();
                sysPermissionData.setId(SnowflakeIdWorker.nextId());
                sysPermissionData.setPermissionId(sysPermission.getId());
                sysPermissionData.setDataId(permissionDataScopeReq.getId());
                // 部门type类型为1
                sysPermissionData.setType(1);
                sysPermissionData.setCreateId(optUserId);
                listSPD.add(sysPermissionData);
            });
            if (listSPD.size() > 0){
                boolean bool = sysPermissionDataService.insertAll(listSPD);
                if (!bool)log.info("添加部门功能页权限范围失败！");
            }
            // 第二步 2): 重新添加当前菜单下的数据员工权限范围
            listSPD.clear();//清空集合
            permissionDataReq.getEmployees().forEach(permissionDataScopeReq -> {
                SysPermissionData sysPermissionData = new SysPermissionData();
                sysPermissionData.setId(SnowflakeIdWorker.nextId());
                sysPermissionData.setPermissionId(sysPermission.getId());
                sysPermissionData.setDataId(permissionDataScopeReq.getId());
                // 员工type类型为2
                sysPermissionData.setType(2);
                sysPermissionData.setCreateId(optUserId);
                listSPD.add(sysPermissionData);
            });
            if (listSPD.size() > 0){
                boolean bool = sysPermissionDataService.insertAll(listSPD);
                if (!bool)log.info("添加员工功能页权限范围失败！");
            }
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean setQuick(long othersUserId, long userId, long optUserId) {
        /**
         * 第一步,先删除userId用户已有菜单权限
         */
        // 先查询出用户已有菜单权限
        List<SysPermission> userPermissions = sysPermissionMapper.selectList(Wrappers.<SysPermission>lambdaQuery()
                .eq(SysPermission::getUserId, userId));

        // 直接删除菜单权限下的数据权限范围
        List<Long> collect = userPermissions.stream().map(e -> e.getId()).collect(Collectors.toList());
        sysPermissionDataMapper.delete(Wrappers.<SysPermissionData>lambdaQuery()
                .in(CollectionUtils.isNotEmpty(collect), SysPermissionData::getPermissionId, collect));

        // 再删除已有菜单权限
        sysPermissionMapper.delete(Wrappers.<SysPermission>lambdaQuery()
                .eq(SysPermission::getUserId, userId));

        /**
         * 第二步,根据othersUserId查询出他人权限后将所有权限赋予指定userId用户
         */
        // 获取他人所有菜单权限
        List<SysPermission> othersUserPermissions = sysPermissionMapper.selectList(Wrappers.<SysPermission>lambdaQuery()
                .eq(othersUserId != 0, SysPermission::getUserId, othersUserId));

        othersUserPermissions.forEach(sysPermission -> {
            Long id = SnowflakeIdWorker.nextId();
            // 获取当前菜单权限是否有数据权限范围
            List<SysPermissionData> sysPermissionDatas = sysPermissionDataMapper.selectList(Wrappers.<SysPermissionData>lambdaQuery()
                    .eq(SysPermissionData::getPermissionId, sysPermission.getId()));

            sysPermissionDatas.forEach(sysPermissionData -> {
                // 修改相关id后插入数据权限范围
                sysPermissionData.setId(SnowflakeIdWorker.nextId());
                // 权限id
                sysPermissionData.setPermissionId(id);
            });
            sysPermissionDataService.insertAll(sysPermissionDatas);

            sysPermission.setId(id);
            sysPermission.setUserId(userId);
            sysPermission.setCreateId(optUserId);
            sysPermission.setModifiedId(null);

        });
        // 将他人权限稍作修改后批量插入权限
        boolean b = super.saveBatch(othersUserPermissions);
        if (b) {
            othersUserPermissions.forEach(item -> newThreadStart(item.getMenuId(), userId, item.getDataType(), optUserId));
        }

        return true;
    }

    @Override
    public PermissionUserMenuDTO queryMenu(Integer sysType, long menuId, long userId) {
        PermissionUserMenuDTO result = new PermissionUserMenuDTO();
        List<PermissionMenuDTO> permissionMenuDTOS;
        if (menuId == 0) {
            List<SysMenu> sysMenu = sysMenuMapper.selectList(Wrappers.<SysMenu>lambdaQuery()
                    .eq(SysMenu::getPlatformSysType, sysType)
                    .eq(SysMenu::getParentId, 0)
                    .eq(SysMenu::getStatus, 1)
                    .eq(SysMenu::getIsDeleted, 0));
            permissionMenuDTOS = EntityUtil.copyList(sysMenu, PermissionMenuDTO.class);
            result.setMenus(permissionMenuDTOS);
            return result;
        }

        List<Object> sysPermissions = sysPermissionMapper.selectObjs(Wrappers.<SysPermission>lambdaQuery().select(SysPermission::getMenuId).eq(userId != 0, SysPermission::getUserId, userId));

        SysMenu sysMenu = sysMenuMapper.selectOne(Wrappers.<SysMenu>lambdaQuery()
                .eq(SysMenu::getId, menuId)
                .eq(SysMenu::getStatus, 1)
                .eq(SysMenu::getIsDeleted, 0));
        List<SysMenu> sysMenus = sysMenuMapper.selectChildrenStatus(menuId);
        sysMenus.add(sysMenu);

        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        // 自定义属性名
        // 默认支持排序
        treeNodeConfig.setWeightKey("sort");
        treeNodeConfig.setChildrenKey("children");

        // 可配置树深度
        treeNodeConfig.setDeep(4);
        treeNodeConfig.setIdKey("id");

        List<Tree<String>> build = new ArrayList<>();
        if (CollUtil.isNotEmpty(sysMenus)) {
            // 转换器
            build = TreeUtil.build(sysMenus, "0", treeNodeConfig,
                    (treeNode, tree) -> {
                        tree.setId(treeNode.getId().toString());
                        tree.setParentId(treeNode.getParentId().toString());
                        tree.setName(treeNode.getTitle());

                        // 扩展属性
                        tree.putExtra("key", treeNode.getId());
                        tree.putExtra("title", treeNode.getTitle());
                        tree.putExtra("sort", treeNode.getSort());
                        tree.putExtra("status", treeNode.getStatus());
                        tree.putExtra("parentIds", sysMenuMapper.selectParentIds(treeNode.getId()));
                    });

        }
        permissionMenuDTOS = JSONArray.parseArray(JSONObject.toJSONString(build), PermissionMenuDTO.class);
        result.setMenus(permissionMenuDTOS);
        result.setOwnMenuIds(sysPermissions);

        return result;
    }

    @Override
    public PermissionDataDTO queryPermissionData(long menuId, long userId) {
        SysPermission sysPermission = sysPermissionMapper.selectOne(Wrappers.<SysPermission>lambdaQuery()
                .eq(SysPermission::getMenuId, menuId)
                .eq(SysPermission::getUserId, userId));
        if (sysPermission == null) {
            throw new BusinessException(SystemError.SYS_411);
        }
        List<SysPermissionData> sysPermissionDatas = sysPermissionDataMapper.selectList(Wrappers.<SysPermissionData>lambdaQuery()
                .eq(SysPermissionData::getPermissionId, sysPermission.getId()));
        List<PermissionDataScopeReq> employees = new ArrayList<>();
        List<PermissionDataScopeReq> depts = new ArrayList<>();
        // 遍历读取数据类型是部门还是员工
        sysPermissionDatas.forEach(sysPermissionData -> {
            PermissionDataScopeReq permissionDataScopeReq = new PermissionDataScopeReq();
            permissionDataScopeReq.setId(sysPermissionData.getDataId());
            if (sysPermissionData.getType() == 1) {
                SysDepartment sysDepartment = sysDepartmentMapper.selectById(sysPermissionData.getDataId());
                permissionDataScopeReq.setTitle(sysDepartment.getTitle());
                depts.add(permissionDataScopeReq);
            } else if (sysPermissionData.getType() == 2) {
                SysUser sysUser = sysUserMapper.selectById(sysPermissionData.getDataId());
                permissionDataScopeReq.setTitle(StrUtil.concat(true, sysUser.getCnSurname(), sysUser.getCnName()));
                employees.add(permissionDataScopeReq);
            }
        });
        PermissionDataDTO result = new PermissionDataDTO();
        result.setDataType(sysPermission.getDataType());
        result.setDepts(depts);
        result.setEmployees(employees);

        return result;
    }

    @Override
    public Result<List<Long>> queryPermission(long menuId, long userId) {
        if (menuId == 0) {
            Result result = new Result();
            result.setCode(SystemError.SYS_409.getCode());
            result.setMsg(String.format(SystemError.SYS_409.getMsg(), menuId));
            return result;
        }
        SysUser sysUser = sysUserMapper.selectById(userId);
        if (sysUser == null || sysUser.getIsDeleted() == 1) {
            return Result.failed(SystemError.USER_1002);
        }
        List<Long> userIds = new ArrayList<>();
        userIds.add(userId);

        if (GlobalConstants.Role.isAdmin(sysUser.getUsername())) {
            List<Long> ids = sysUserMapper.selectObjs(Wrappers.<SysUser>lambdaQuery().select(SysUser::getId)).stream().map(o -> (Long) o).collect(Collectors.toList());
            userIds.addAll(ids);
            return Result.success(userIds);
        }

        // 先查询功能权限
        SysPermission sysPermission = sysPermissionMapper.selectOne(Wrappers.<SysPermission>lambdaQuery()
                .eq(SysPermission::getMenuId, menuId)
                .eq(SysPermission::getUserId, userId));
        if (sysPermission == null) {
            return Result.failed(SystemError.SYS_401);
        }

        // 权限类型
        if (sysPermission.getDataType() == 1) {
            // 全公司
            List<Long> ids = sysUserMapper.selectObjs(Wrappers.<SysUser>lambdaQuery().select(SysUser::getId)).stream().map(o -> (Long) o).collect(Collectors.toList());
            userIds.addAll(ids);
        } else if (sysPermission.getDataType() == 2) {
            // 仅部门
            List<Long> ids = sysDepartmentService.queryUserIdsByDeptId(sysUser.getDeptId());
            userIds.addAll(ids);
        } else if (sysPermission.getDataType() == 3) {
            // 仅自己
        } else if (sysPermission.getDataType() == 4) {
            // 自定义
            // 再根据功能权限id查询数据权限范围
            List<SysPermissionData> sysPermissionDatas = sysPermissionDataMapper.selectList(Wrappers.<SysPermissionData>lambdaQuery()
                    .eq(SysPermissionData::getPermissionId, sysPermission.getId()));

            // 遍历读取数据类型是部门还是员工
            sysPermissionDatas.forEach(sysPermissionData -> {
                PermissionDataScopeReq permissionDataScopeReq = new PermissionDataScopeReq();
                permissionDataScopeReq.setId(sysPermissionData.getDataId());
                if (sysPermissionData.getType() == 1) {
                    // 数据权限是部门,则通过部门id获取部门所有员工
                    List<SysUser> users = sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getDeptId, sysPermissionData.getDataId()));
                    // 将用户集合id快速插入list中
                    userIds.addAll(users.stream().map(user -> user.getId()).collect(Collectors.toList()));
                } else if (sysPermissionData.getType() == 2) {
                    // 数据类型是员工,则直接插入list中
                    userIds.add(sysPermissionData.getDataId());
                }
            });
        }

        return Result.success(userIds.stream().distinct().collect(Collectors.toList()));
    }

    @Override
    public Set<Long> queryPermissionUserIdByMenuId(long menuId) {
        if (menuId == 0) return null;
        // 只要看见这一个菜单即可
        List<SysPermission> sysPermissions = sysPermissionMapper.selectList(Wrappers.<SysPermission>lambdaQuery()
                .eq(SysPermission::getMenuId, menuId));
        if (sysPermissions != null && sysPermissions.size() > 0) {
            Set<Long> ids = sysPermissions.stream().map(e -> e.getUserId()).collect(Collectors.toSet());
            return ids;
        }
        return null;
    }

    private void newThreadStart(Long menuId, Long userId, Integer dataType, Long optUserId) {
        List<SysMenuActionButtonDTO> smab = sysMenuService.queryActionButton(menuId, userId);
        if (smab != null && smab.size() > 0) {
            List<Long> collect = smab.stream().map(e -> e.getId()).collect(Collectors.toList());
            //默认设置按钮权限
            PermissionDataReq pdr = new PermissionDataReq();
            pdr.setButtonIds(collect);
            pdr.setDataType(dataType);
            pdr.setUserId(userId);
            pdr.setMenuId(menuId);
            try {
                setMenuPermissionData(pdr, optUserId);
            } catch (Exception e) {
                //不做处理
            }
        }
        //任务太多启动多个线程去添加
//        new Thread(() -> {
//        }).start();
    }
}
